package indi.yuluo.controller;

import indi.yuluo.common.BaseContext;
import indi.yuluo.core.RedisTemplate;
import indi.yuluo.entity.user.UserInfo;
import indi.yuluo.exception.LoginException;
import indi.yuluo.service.UserRoleService;
import indi.yuluo.service.UserService;
import indi.yuluo.util.MD5Util;
import indi.yuluo.util.UuidUtil;
import indi.yuluo.vo.Msg;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Objects;

/**
 * @Author: yuluo
 * @CreateTime: 2022-07-19  18:46
 * @Description: 用户控制器
 */

@RestController
@RequestMapping(value = "/user")
@Slf4j
@Api(value = "用户业务相关类")
public class UserController {

    @Resource
    private UserService userService;

    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 用户登录
     *
     * @param username 用户名
     * @return
     */
    @PostMapping(value = "/login")
    @ApiOperation(value = "根据用户名获取用户信息", httpMethod = "POST", notes = "用于用户登录")
    public Msg getUserByUsername(@RequestParam String username, @RequestParam String password) {

        UserInfo userByUsername = userService.getUserByUsername(username);
        // 处于安全考虑，密码使用md5加密
        String currentPassword = MD5Util.getMD5(password);

        // 1、验证用户名是否存在，不存在将异常信息返回给前端
        if (Objects.isNull(userByUsername)) {
            throw new LoginException("用户名不存在！");
        }

        // 2、用户名存在之后，验证密码，密码错误抛出异常信息 从数据库查出来的用户密码和在前端页面传过来的登录密码比对
        String userPassword = userByUsername.getPassword();
        log.info("当前用户密码： {}", currentPassword);
        log.info("数据库用户密码：{}", userPassword);

        if (!Objects.equals(userPassword, currentPassword)) {
            throw new LoginException("密码错误！");
        }

        // 3、检查完毕之后，将用户信息存到redis中，用于缓存用户信息
        // 生成uuid
        String uuid = UuidUtil.getUuid();
        redisTemplate.setObject(uuid, userByUsername, 18000L);

        // 给前端返回一个token值，用于校验用户登录状态，在过滤器器中拦截请求，查看redis中是否有对应的用户信息
        return Msg.success().add("token", uuid);
    }

    @PostMapping("/logout")
    @ApiOperation(value = "用户退出登录", httpMethod = "POST", notes = "从redis中删除对应token的用户登录信息")
    public Msg logout(@RequestParam String token) {

        boolean flag = false;

        // 消除redis中的用户信息，消除登录依据
        long remove = redisTemplate.remove(token);

        if (!Objects.equals(remove, 0L)) {
            flag = true;
        }

        return flag ? Msg.success() : Msg.fail();
    }

    /**
     * 检验用户名的唯一性，确保不会重复
     *
     * @param username 用户注册时输入的用户名
     * @return
     */
    @GetMapping("/checkUsername")
    @ApiOperation(value = "检验用户名唯一性", httpMethod = "GET", notes = "用于用户注册时的用户名检验")
    public Msg checkUsername(@RequestParam String username) {

        boolean flag = true;

        UserInfo userInfo = userService.getUserByUsername(username);
        if (Objects.equals(userInfo.getUsername(), username)) {
            // 如果从数据库查出来的值和前端传过来的值相同，就说明重复了
            flag = false;
        }

        return flag ? Msg.success() :Msg.fail();
    }

    /**
     * 用户注册，同时进行用户名和密码校验
     *
     * @param userInfo 用户对象
     * @return 注册结构
     */
    @PostMapping("/register")
    @ApiOperation(value = "用户注册", httpMethod = "POST", notes = "用户注册数据库操作")
    public Msg register(@RequestBody @Valid UserInfo userInfo, BindingResult result) {

        // 进行用户信息校验
        if (result.hasErrors()) {
            String message = Objects.requireNonNull(result.getFieldError()).getDefaultMessage();
            return Msg.fail().add("msg", message);
        }

        // 校验成功之后，存入数据中
        userService.saveUser(userInfo.getUsername(), userInfo.getPassword());

        return Msg.success();
    }

    /**
     * 添加用户的个人信息
     * @param userInfo
     * @return
     */
    @PostMapping("/changeUserInfo")
    @ApiOperation(value = "修改和添加用户信息", httpMethod = "POST", notes = "添加用户信息至数据库")
    public Msg addUserInformation(UserInfo userInfo) {

        // log.info("changeUserInfo: 线程名{}", Thread.currentThread().getName());

        // 获取用户的uuid值
        log.info("用户的uuid：{}", BaseContext.getUuid());

        userInfo.setUuid(BaseContext.getUuid());

        boolean flag = userService.addUserInformation(userInfo);

        return flag ? Msg.success() : Msg.fail();
    }

    /**
     * 获取用户信息返回给前端
     * @param token
     * @return
     */
    @GetMapping("/getUserInfoByToken")
    @ApiOperation(value = "获取用户信息返回给前端", httpMethod = "GET")
    public Msg getUserInfoByToken(String token) {

        boolean flag = false;

        UserInfo userByToken = userService.getUserByToken(token);

        if (Objects.nonNull(userByToken)) {
            flag = true;
        }

        // log.info("getUserInfoByToken: 线程名{}", Thread.currentThread().getName());
        // 设置到ThreadLocal域中
        // BaseContext.setCurrent(String.valueOf(userByToken.getUuid()));

        BaseContext.setUuid(userByToken.getUuid());

        return flag ? Msg.success().add("userInfo", userByToken) : Msg.fail().add("error", "获取用户信息失败！请稍后重试");
    }


}
